<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Solr.php
 *
 * Makes Solr-PHP-Client work with CodeIgniter.  This
 * has been written to make Solr work like the default
 * CodeIgniter DB class.  Although this is not how is
 * Solr-PHP-Client is designed to work, this will make
 * learning Solr access much easier for other developers.
 *
 * This class is written for PHP5 as the Solr-PHP-Client
 * would need considerable reworking to make it work in
 * PHP4.
 *
 * @author ONIPHP CO.,LTD (http://www.oniphp.com)
 */

/* Add the class in */
require_once(APPPATH.'libraries/SolrPHPClient/Service.php');

class CI_Solr extends Apache_Solr_Service {
    /* Codeigniter object */
    var $hostname;
    var $port;
    var $path;
	var $connected = false;
	var $offset = 0;
	var $limit = 20;
		
    function __construct()
    {
        /* Get CI */
        $this->_objCI = &get_instance();		
        /* Load the config */
        $this->hostname = $this->_objCI->config->item('solr_hostname');
        $this->port = $this->_objCI->config->item('solr_port');
        $this->path = $this->_objCI->config->item('solr_path');	
        /* No point connecting twice */
        if(!$this->connected) {
            /* Connect to Solr - strictly speaking, you don't need vars here */
            parent::__construct($this->hostname, $this->port, $this->path);

            /* Test the connection */
            if($this->ping() !== false) {
                /* Worked - set connection */
                $this->connected = true;
                return $this->connected;
            } else {
                /* Connection failed - throw error? */
                $msg = 'Solr failed to connect - host: {'.$this->hostname.'}, port: {'.$this->port.'}, path: {'.$this->path.'}';
                log_message('debug', $msg);
            }
        }		
    }
	
	final public function cleanParam()
	{		
		$this->query = '';		
		$this->offset = 0;
		$this->limit = 20;
		$this->order_by = '';
	}	

    /**
     * query
     *
     * Runs the query and outputs as an associative
     * array.
     * 
     * This is a bit weird as the Apache Document object
     * doesn't return an array function - instead, it
     * returns the values and the keys separately.  There
     * might be a perfectly good reason as to why they've
     * done it that way, but it seems a bit odd to me.
     * 
     * @return array/false
     */	
	final public function query($query)
	{
		$this->query = $query;
		return $this;
	}

    /**
     * limit
     *
     * @return array
     */		
	final public function limit($offset=0,$limit=NULL)
	{
		if(empty($limit)):
			$this->offset = 0;
			$this->limit = $offset;
		else:
			$this->offset = $offset;
			$this->limit = $limit;		
		endif;	
		return $this;
	}
	
    /**
     * limit
     *
     * @return array
     */		
	final public function order_by($order_by = array())
	{
		if(is_array($order_by)):
			$this->order_by = '';
			foreach($order_by as $key => $value):
				$this->order_by .= strtolower($key.' '.$value).' ';
			endforeach;
		else:
			$this->order_by = strtolower($order_by);
		endif;
		return $this;
	}	

    /**
     * count
     *
     * @return number
     */		
	final public function count_all_results()
	{
		// in production code you'll always want to use a try / catch for any
		// possible exceptions emitted  by searching (i.e. connection
		// problems or a query parsing error)
		try
		{
			if(!empty($this->order_by)):
				$this->query = $this->search($this->query, $this->offset, $this->limit,array('sort' => $this->order_by));	
			else:
				$this->query = $this->search($this->query, $this->offset, $this->limit);
			endif;
		}
		catch(Exception $e){
			// in production you'd probably log or email this error to an admin
			// and then show a special message to the user but for this example
			// we're going to show the full exception
			die("<html><head><title>SEARCH EXCEPTION</title><body><pre>{$e->__toString()}</pre></body></html>");
		}
		
		$data = $this->query->response->numFound;
		
		$this->cleanParam(); //clean data

		return $data;
	}

    /**
     * result
     *
     * @return array
     */		
	final public function result()
	{
		// in production code you'll always want to use a try / catch for any
		// possible exceptions emitted  by searching (i.e. connection
		// problems or a query parsing error)
		try
		{
			if(!empty($this->order_by)):
				$this->query = $this->search($this->query, $this->offset, $this->limit,array('sort' => $this->order_by));	
			else:
				$this->query = $this->search($this->query, $this->offset, $this->limit);
			endif;
		}
		catch(Exception $e){
			// in production you'd probably log or email this error to an admin
			// and then show a special message to the user but for this example
			// we're going to show the full exception
			die("<html><head><title>SEARCH EXCEPTION</title><body><pre>{$e->__toString()}</pre></body></html>");
		}
		  
		if($this->query->response->numFound != 0):
			$data = new stdClass;
			$doc = $this->query->response->docs;
			foreach($doc as $key => $item):
			  	foreach ($item as $field => $value):
					$data->{$key}->{$field} = $value;
				endforeach;
			endforeach;
		else:
			$data = array();
		endif;
		
		$this->cleanParam(); //clean data

		return $data;
	}
	
    /**
     * result
     *
     * @return array
     */		
	final public function row()
	{
		// in production code you'll always want to use a try / catch for any
		// possible exceptions emitted  by searching (i.e. connection
		// problems or a query parsing error)
		try
		{
			if(!empty($this->order_by)):
				$this->query = $this->search($this->query,'','',$this->order_by);	
			else:
				$this->query = $this->search($this->query);
			endif;
		}
		catch(Exception $e){
			// in production you'd probably log or email this error to an admin
			// and then show a special message to the user but for this example
			// we're going to show the full exception
			die("<html><head><title>SEARCH EXCEPTION</title><body><pre>{$e->__toString()}</pre></body></html>");
		}
		
		if($this->query->response->numFound != 0):
			$data = new stdClass;
			$doc = $this->query->response->docs;
			foreach ($doc[0] as $field => $value):
				$data->{$field} = $value;
			endforeach;		
		else:
			$data = '';
		endif;
		
		$this->cleanParam(); //clean data
			
		return $data;
	}	

  	final public function escapeSolrValue($string)
	{
		$string_arr = explode(',',$string);
		$string_pack = array();
		if(!empty($string_arr[0])) foreach($string_arr as $value):
			$match = array('\\', '+', '-', '&', '|', '!', '(', ')', '{', '}', '[', ']', '^', '~', '*', '?', ':', '"', ';');
			$replace = array('\\\\', '\\+', '\\-', '\\&', '\\|', '\\!', '\\(', '\\)', '\\{', '\\}', '\\[', '\\]', '\\^', '\\~', '\\*', '\\?', '\\:', '\\"', '\\;');	
			$string_pack[] = str_replace($match, $replace, $value);		
		endforeach;
		return implode(',',$string_pack);
	}
}
?>